package com.fduss.mazegame.core.unit;

import com.fduss.mazegame.core.maze.Map;
import com.fduss.mazegame.core.unit.feature.HasIcon;
import com.fduss.mazegame.core.unit.feature.Icon;
import com.fduss.mazegame.util.Direction;
import com.fduss.mazegame.util.List;
import com.fduss.mazegame.util.ListArray;

import java.util.NoSuchElementException;

/**
 * Maps are a 2D array of Places(cell): Walls and Spaces.
 *
 * @author Duocai Wu
 * @Date 2017/10/05
 */
public abstract class Place implements HasIcon {
    protected Icon icon;
    private int row;
    private int col;
    private boolean isVisit;
    private Map map;
    private List<Entity> entityList = new ListArray<>();

    protected Place(Icon icon) {
        this.icon = icon;
    }

    public Icon getIcon() {
        if (getEntiesNum() <= 0)
            return icon;
        else
            return getEntity(getEntiesNum() - 1).getIcon();
    }

    public abstract boolean isWalkable();

    public void addEntity(Entity entity) {
        entityList.add(entity);
    }

    public void rmEntity(Entity entity) {
        try {
            entityList.remove(entityList.indexOf(entity));
        } catch (NoSuchElementException ignored) {
        }
    }

    public int getEntiesNum() {
        return entityList.size();
    }

    public Entity getEntity(int i) {
        return entityList.get(i);
    }

    /**
     * // Returns null if the destination place is out of the maze.
     *
     * @param dir
     * @return
     */
    public Place placeAt(Direction dir) {
        if (dir == null) {
            throw new NullPointerException("dir");
        }
        int dstRow = getRow();
        int dstCol = getCol();
        switch (dir) {
            case NORTH:
                dstRow--;
                break;
            case SOUTH:
                dstRow++;
                break;
            case EAST:
                dstCol++;
                break;
            case WEST:
                dstCol--;
                break;
            default:
                throw new UnsupportedOperationException(
                        dir.toString());
        }
        if (dstRow < 0 || dstRow >= map.getNumRows() ||
                dstCol < 0 || dstCol >= map.getNumCols()) {
            return null;
        }
        return map.getPlace(dstRow, dstCol);
    }

    public boolean equals(Object o) {
        if (!(o instanceof Place)) {
            return false;
        }
        Place p = (Place) o;
        return (this.getRow() == p.getRow()) &&
                (this.getCol() == p.getCol()) &&
                (this.map.equals(p.map));
    }

    public int getRow() {
        return row;
    }

    public int getCol() {
        return col;
    }

    public Map getMap() {
        return map;
    }

    public void setMap(Map map) {
        this.map = map;
    }

    public void setPlace(int i, int j) {
        row = i;
        col = j;
    }

    public boolean isVisit() {
        return isVisit;
    }

    public void setVisit(boolean visit) {
        isVisit = visit;
    }
}
